/**
 * Created by Freeman on 2016/8/2.
 */
import merge from 'lodash/merge'
import union from 'lodash/union'

// Creates a reducer managing pagination, given the action types to handle,
// and a function telling how to extract the key from an action.
export default function paginate({ types, mapActionToKey }) {
    if (!Array.isArray(types) || types.length !== 3) {
        throw new Error('Expected types to be an array of three elements.')
    }
    if (!types.every(t => typeof t === 'string')) {
        throw new Error('Expected types to be strings.')
    }
    if (typeof mapActionToKey !== 'function') {
        throw new Error('Expected mapActionToKey to be a function.')
    }

    const [ requestType, successType, failureType ] = types

    function updatePagination(state = {
        isFetching: false,
        nextPageUrl: undefined,
        pageCount: 0,
        ids: []
    }, action) {
        switch (action.type) {
            case requestType:
                return merge({}, state, {
                    isFetching: true
                })
            case successType:
                return merge({}, state, {
                    isFetching: false,
                    ids: union(state.ids, action.response.result),
                    nextPageUrl: action.response.nextPageUrl,
                    pageCount: state.pageCount + 1
                })
            case failureType:
                return merge({}, state, {
                    isFetching: false
                })
            default:
                return state
        }
    }

    return function updatePaginationByKey(state = {}, action) {
        switch (action.type) {
            case requestType:
            case successType:
            case failureType:
                const key = mapActionToKey(action)
                if (typeof key !== 'string') {
                    throw new Error('Expected key to be a string.')
                }
                return merge({}, state, {
                    [key]: updatePagination(state[key], action)
                })
            default:
                return state
        }
    }
}